//
//  MFAPMManager.m
//  MFAPMManager
//
//  Created by zhang liyu on 2019/5/22.
//

#import "MFAPMManager.h"

#import "MFAPMNetMonitorURLProtocol.h"
#import "MFAPMAppLifeCircleProtocol.h"
#import "MFAPMScreenShotMonitor.h"
#import "MFAPMLocationMonitor.h"
#import "MFAPMUploadManager.h"
#import "MFAPMCrashMonitor.h"
#import "MFAPMDataFactory.h"
#import "MFAPMBaseModel.h"
#import "MFAPMConfig.h"

@interface MFAPMManager ()

@property (nonatomic, readwrite, getter=isMonitorEnabled, assign) BOOL monitorEnabled;

/**
 日志上传的计时器，当触发定时事件时，进行内存中日志的上传操作
 */
@property (nonatomic, strong) dispatch_source_t uploadTimer;

/**
 记录当前上传计时器是否已经开启计时，YES：已开启 NO：未开启，默认为NO
 */
@property (nonatomic, assign) BOOL isUploadTimerResume;

/**
 记录启动事件的model
 */
@property (nonatomic, strong) MFAPMBaseModel *launchModel;

/**
 记录启动事件发生的时间，单位毫秒
 */
@property (nonatomic, assign) NSTimeInterval launchTime;

@end

@implementation MFAPMManager

#pragma mark - Singleton

+ (instancetype)sharedManager{
    static MFAPMManager *manager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[MFAPMManager alloc] init];
    });
    return manager;
}

#pragma mark - Life Circle

- (void)dealloc{
    [self stopMonitor];
}

- (void)awakeFromNib{
    [super awakeFromNib];
    [self initialActions];
}

- (instancetype)init{
    self = [super init];
    if(self){
        [self initialActions];
    }
    return self;
}

- (void)initialActions{
    _monitorEnabled = NO;
    _config = nil;
    _isUploadTimerResume = NO;
    _launchTime = 0;
}

#pragma mark - Monitor Actions

- (void)startMonitorWithUserId:(nullable NSString *)userId{
    
    //更新数据工厂中的用户id
    [MFAPMDataFactory updateUserID:userId];
    
    //添加监听，避免错过事件调用时机
    [self registerNotifications];
    
    //更新配置请求,并在结束后进行对应功能的开启
    __weak typeof (&*self) weakSelf = self;
    [[MFAPMConfig defaultConfigure] fetchSettingConfigWithComplete:^{
        __strong typeof (&*self) strongSelf = weakSelf;
        [strongSelf configMonitor];
    }];
}

- (void)stopMonitor{
    
    //移除监听对象
    [self removeNotifications];
    
    //未开启监听，不用处理结束监听操作
    if(!_monitorEnabled){
        return;
    }
    
    _monitorEnabled = NO;
    _config = nil;
    
    [[MFAPMNetMonitorURLProtocol sharedInstance] stopMonitor];
    [[MFAPMScreenShotMonitor sharedInstance] stopMonitor];
    [[MFAPMCrashMonitor sharedInstance] stopMonitor];
    
    //停止事件上传计时器
    if(_uploadTimer){
        dispatch_cancel(_uploadTimer);
        self.isUploadTimerResume = NO;
    }
    
    //关闭地理定位监听
    [[MFAPMLocationMonitor sharedInstance] stopMonitor];
}

- (void)configMonitor{
    _monitorEnabled = [MFAPMConfig defaultConfigure].apmEnable;
    //总开关关闭时，关闭监听，直接返回
    if(!_monitorEnabled){
        _config = nil;
        return;
    }
    //开启监听服务
    _config = [MFAPMConfig defaultConfigure];
    
    //判断服务是否开启
    
    //网络请求监听
    if([MFAPMConfig defaultConfigure].netErrorEnable){
        [[MFAPMNetMonitorURLProtocol sharedInstance] startMonitor];
    }
    //崩溃监听
    if([MFAPMConfig defaultConfigure].crashEnable){
        [[MFAPMCrashMonitor sharedInstance] startMonitor];
    }
    //截图监听
    if([MFAPMConfig defaultConfigure].screenshotEnable){
        [[MFAPMScreenShotMonitor sharedInstance] startMonitor];
    }
    
    //开启事件上传计时器
    if (!self.isUploadTimerResume) {
        dispatch_resume(self.uploadTimer);
        self.isUploadTimerResume = YES;
    }
    
    //开启地理定位监听
    [[MFAPMLocationMonitor sharedInstance] startMonitor];
    
    //开启监听后，当首次启动事件没有上传，则进行首次启动上传操作
    __weak typeof(&*self) weakSelf = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        __strong typeof(&*self) strongSelf = weakSelf;
        if(strongSelf.launchTime > 0){
            [strongSelf uploadLaunchEvent];
            strongSelf.launchTime = 0;
        }
    });
}

#pragma mark - Notification Actions

- (void)registerNotifications{
    
    //程序完成启动
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidFinishLaunching:) name:UIApplicationDidFinishLaunchingNotification object:nil];
    
    //进入前台
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
    
    //进入后台
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil];
    
    //将要停止
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillTerminate:) name:UIApplicationWillTerminateNotification object:nil];
    
    //网络状态更改
}

- (void)removeNotifications{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

#pragma mark - Notification Deal Actions

- (void)appDidFinishLaunching:(NSNotification *)notification{
    //生成启动事件时间
    self.launchTime = [[NSDate date] timeIntervalSince1970] * 1000;
}

- (void)appDidBecomeActive:(NSNotification *)notification{
    if(_monitorEnabled){
        //进入前台，恢复上传事件计时器
        if (!self.isUploadTimerResume) {
            dispatch_resume(self.uploadTimer);
            self.isUploadTimerResume = YES;
        }
        [[self.config fetchAppLifeCircleInterceptors] enumerateObjectsUsingBlock:^(id<MFAPMAppLifeCircleProtocol>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            if([obj conformsToProtocol:@protocol(MFAPMAppLifeCircleProtocol)]
               && [obj respondsToSelector:@selector(appDidBecomeActive:)]){
                [obj appDidBecomeActive:notification];
            }
        }];
    }
}

- (void)appWillResignActive:(NSNotification *)notification{
    if(_monitorEnabled){
        //进入后台，挂起上传事件计时器
        if (self.isUploadTimerResume) {
            dispatch_suspend(self.uploadTimer);
            self.isUploadTimerResume = NO;
        }
        //进入后台，进行缓存日志的上传操作
        [MFAPMUploadManager uploadCacheDataNow];
        
        [[self.config fetchAppLifeCircleInterceptors] enumerateObjectsUsingBlock:^(id<MFAPMAppLifeCircleProtocol>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            if([obj conformsToProtocol:@protocol(MFAPMAppLifeCircleProtocol)]
               && [obj respondsToSelector:@selector(appWillResignActive:)]){
                [obj appWillResignActive:notification];
            }
        }];
    }
}

- (void)appWillTerminate:(NSNotification *)notification{
     if(_monitorEnabled){
         //将要停止时，进行内存中数据的缓存操作
         [MFAPMUploadManager storeCacheItemsToDiskNow];
         
         [[self.config fetchAppLifeCircleInterceptors] enumerateObjectsUsingBlock:^(id<MFAPMAppLifeCircleProtocol>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
             if([obj conformsToProtocol:@protocol(MFAPMAppLifeCircleProtocol)]
                && [obj respondsToSelector:@selector(appWillTerminate:)]){
                 [obj appWillTerminate:notification];
             }
         }];
     }
    
    //停止事件的监听操作
    [self stopMonitor];
}

/**
 上传启动事件，同数据库及内存中事件一同上传
 */
- (void)uploadLaunchEvent{
    
    //生成启动事件
    self.launchModel = [[MFAPMBaseModel alloc] init];
    self.launchModel.eventType = 4;
    self.launchModel.timestamp = self.launchTime;
    
    //上传事件
    [MFAPMUploadManager uploadCacheDataNowWithItem:self.launchModel];
    //清空启动事件
    self.launchModel = nil;
    
    //代理对象数组更新事件
    [[self.config fetchAppLifeCircleInterceptors] enumerateObjectsUsingBlock:^(id<MFAPMAppLifeCircleProtocol>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if([obj conformsToProtocol:@protocol(MFAPMAppLifeCircleProtocol)]
           && [obj respondsToSelector:@selector(appDidFinishLaunching:)]){
            [obj appDidFinishLaunching:nil];
        }
    }];
}

#pragma mark - Setter & Getter

- (dispatch_source_t)uploadTimer{
    if(!_uploadTimer){
        _uploadTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
        
        CGFloat timerInterval = self.config.uploadInterval * NSEC_PER_SEC;
        dispatch_time_t startTime = dispatch_time(DISPATCH_TIME_NOW, timerInterval);
        dispatch_source_set_timer(_uploadTimer, startTime, timerInterval, 0);
        
        dispatch_source_set_event_handler(_uploadTimer, ^{
            [MFAPMUploadManager uploadCacheDataNow];
        });
    }
    return _uploadTimer;
}

@end
